package com.hit.RuningGirl.screen;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.objects.EllipseMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell;
import com.badlogic.gdx.maps.tiled.TmxMapLoader;
import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.ChainShape;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.hit.RuningGirl.main.Yelling;

import static com.hit.RuningGirl.handle.Constant.FLOOR;
import static com.hit.RuningGirl.handle.Constant.PLAYER;
import static com.hit.RuningGirl.handle.Constant.RATE;
import static com.hit.RuningGirl.handle.Constant.SPEED;
import static com.hit.RuningGirl.handle.Constant.STAR;
import static com.hit.RuningGirl.handle.Constant.TRAP;
import static com.hit.RuningGirl.handle.Constant.ZHIZHANG;
import static com.hit.RuningGirl.handle.Constant.FLAME;
import static com.hit.RuningGirl.main.Yelling.ViewPort_HEIGHT;
import static com.hit.RuningGirl.main.Yelling.ViewPort_WIDTH;
import static com.hit.RuningGirl.main.Yelling.assetManager;
import static com.hit.RuningGirl.main.Yelling.mainScreen;

public class GameScreen extends YellScreen {

    private boolean Box2DDebug = true;

    private World world;

    private Box2DDebugRenderer box2dRender;

    private OrthographicCamera box2dCamera;

    private com.hit.RuningGirl.handle.Box2DContactListener bcl;

    Body body;

    private TiledMap tileMap;

    private float tileSize;

    private float mapWidth;

    private float mapHeight;

    private OrthogonalTiledMapRenderer mapRender;

    public static int level;

    public com.hit.RuningGirl.sprite.Protagonist protagonist;

    private float statetime;

    private Array<com.hit.RuningGirl.sprite.Star> stars;

    private Array<com.hit.RuningGirl.sprite.ZhiZhang> zaw;

    private Array<com.hit.RuningGirl.sprite.Flame> flames;

    private com.hit.RuningGirl.handle.YellingRobot robot;


    private com.hit.RuningGirl.sprite.GameBack gameBack;

    //创建陷阱数组
    private Array<com.hit.RuningGirl.sprite.Trap> traps;


    public GameScreen(Yelling game) {
        super(game);

        bcl = new com.hit.RuningGirl.handle.Box2DContactListener();

        world = new World(new Vector2(0, -9.81f), true);

        world.setContactListener(bcl);

        box2dRender = new Box2DDebugRenderer();

        box2dCamera = new OrthographicCamera();

        box2dCamera.setToOrtho(false, ViewPort_WIDTH / RATE, ViewPort_HEIGHT / RATE);


        this.init();
    }

    public void init() {

        createActor();

        createMap();

        createStar();

        createZhiZhang();

        //创建陷阱
        createTrap();
        //创建火焰怪物
        createFlame();

        gameBack = new com.hit.RuningGirl.sprite.GameBack();


    }

    /**
     * 创建火焰怪物
     */
    private void createFlame() {

        // 实例化火焰对象数组
        flames = new Array<com.hit.RuningGirl.sprite.Flame>();
        // 遍历火焰对象层
        MapLayer ml = tileMap.getLayers().get("flame");
        // 对象层为空即返回
        if (ml == null) return;
        // 定义刚体样式
        BodyDef bodyDef = new BodyDef();
        // 定义刚体类型
        bodyDef.type = BodyType.StaticBody;
        // 实例化圆形图形
        CircleShape shape = new CircleShape();
        // 设置圆形图形半径
        shape.setRadius(5 / RATE);
        // 实例化夹具
        FixtureDef fixtureDef = new FixtureDef();
        // 绑定图形与刚体
        fixtureDef.shape = shape;
        // 设置刚体为传感器
        fixtureDef.isSensor = true;
        // 设定刚体自身碰撞属性
        fixtureDef.filter.categoryBits = FLAME;
        // 设定刚体目标碰撞属性
        fixtureDef.filter.maskBits = PLAYER;
        // 遍历火焰对象层
        for (MapObject mo : ml.getObjects()) {
            // 对象x,y轴坐标
            float x = 0;
            float y = 0;
            // 遍历图层对象
            if (mo instanceof EllipseMapObject) {
                EllipseMapObject emo = (EllipseMapObject) mo;
                // 赋值火焰对象x，y坐标
                x = emo.getEllipse().x / RATE;
                y = emo.getEllipse().y / RATE;
            }
            // 设定刚体位置
            bodyDef.position.set(x, y);
            // 实例化刚体
            Body body = world.createBody(bodyDef);
            // 实例化夹具并且设定夹具用户数据
            body.createFixture(fixtureDef).setUserData("flame");
            // 实例化火焰对象
            com.hit.RuningGirl.sprite.Flame f = new com.hit.RuningGirl.sprite.Flame(body);
            // 设定刚体用户数据
            body.setUserData(f);
            // 添加火焰对象到火焰数组
            flames.add(f);
        }
        shape.dispose();
    }

    /**
     * 创建陷阱
     */
    private void createTrap() {

        // 实例化火焰对象数组
        traps = new Array<com.hit.RuningGirl.sprite.Trap>();
        // 遍历火焰对象层
        MapLayer ml = tileMap.getLayers().get("trap");
        // 对象层为空即返回
        if (ml == null) return;
        // 定义刚体样式
        BodyDef bodyDef = new BodyDef();
        // 定义刚体类型
        bodyDef.type = BodyType.StaticBody;
        // 实例化圆形图形
        CircleShape shape = new CircleShape();
        // 设置圆形图形半径
        shape.setRadius(5 / RATE);
        // 实例化夹具
        FixtureDef fixtureDef = new FixtureDef();
        // 绑定图形与刚体
        fixtureDef.shape = shape;
        // 设置刚体为传感器
        fixtureDef.isSensor = true;
        // 设定刚体自身碰撞属性
        fixtureDef.filter.categoryBits = TRAP;
        // 设定刚体目标碰撞属性
        fixtureDef.filter.maskBits = PLAYER;
        // 遍历火焰对象层
        for (MapObject mo : ml.getObjects()) {
            // 对象x,y轴坐标
            float x = 0;
            float y = 0;
            // 遍历图层对象
            if (mo instanceof EllipseMapObject) {
                EllipseMapObject emo = (EllipseMapObject) mo;
                // 赋值火焰对象x，y坐标
                x = emo.getEllipse().x / RATE;
                y = emo.getEllipse().y / RATE;
            }
            // 设定刚体位置
            bodyDef.position.set(x, y);
            // 实例化刚体
            Body body = world.createBody(bodyDef);
            // 实例化夹具并且设定夹具用户数据
            body.createFixture(fixtureDef).setUserData("trap");
            // 实例化火焰对象
            com.hit.RuningGirl.sprite.Trap f = new com.hit.RuningGirl.sprite.Trap(body);
            // 设定刚体用户数据
            body.setUserData(f);
            // 添加火焰对象到火焰数组
            traps.add(f);
        }
        shape.dispose();
    }


    private void createZhiZhang() {

        zaw = new Array<com.hit.RuningGirl.sprite.ZhiZhang>();

        MapLayer ml = tileMap.getLayers().get("zhizhang");

        if (ml == null) return;

        BodyDef bodyDef = new BodyDef();

        bodyDef.type = BodyType.StaticBody;

        CircleShape shape = new CircleShape();

        shape.setRadius(5 / RATE);

        FixtureDef fixtureDef = new FixtureDef();

        fixtureDef.shape = shape;

        fixtureDef.isSensor = true;

        fixtureDef.filter.categoryBits = ZHIZHANG;

        fixtureDef.filter.maskBits = PLAYER;

        for (MapObject mo : ml.getObjects()) {

            float x = 0;
            float y = 0;

            if (mo instanceof EllipseMapObject) {
                EllipseMapObject emo = (EllipseMapObject) mo;

                x = emo.getEllipse().x / RATE;
                y = emo.getEllipse().y / RATE;
            }

            bodyDef.position.set(x, y);

            Body body = world.createBody(bodyDef);

            body.createFixture(fixtureDef).setUserData("flame");

            com.hit.RuningGirl.sprite.ZhiZhang f = new com.hit.RuningGirl.sprite.ZhiZhang(body);

            body.setUserData(f);

            zaw.add(f);
        }
        shape.dispose();
    }

    private void createActor() {

        BodyDef bodyDef = new BodyDef();

        FixtureDef fixtureDef = new FixtureDef();

        PolygonShape shape = new PolygonShape();

        body = world.createBody(bodyDef);

        bodyDef.position.set(60 / RATE, 200 / RATE);

        bodyDef.type = BodyType.DynamicBody;

        bodyDef.linearVelocity.set(SPEED, 0);


        body = world.createBody(bodyDef);

        shape.setAsBox(15 / RATE, 25 / RATE);

        fixtureDef.shape = shape;

        fixtureDef.filter.categoryBits = PLAYER;


        //是专业
        fixtureDef.filter.maskBits = FLOOR | STAR | ZHIZHANG | FLAME | TRAP;

        body.createFixture(fixtureDef).setUserData("box");

        shape.setAsBox(15 / RATE, 5 / RATE, new Vector2(0, -25 / RATE), 0);

        fixtureDef.shape = shape;

        fixtureDef.filter.categoryBits = PLAYER;

        fixtureDef.filter.maskBits = FLOOR;

        fixtureDef.isSensor = true;

        body.createFixture(fixtureDef).setUserData("foot");

        protagonist = new com.hit.RuningGirl.sprite.Protagonist(body);
    }

    private void createMap() {
        // 加载地图

        // 实例化地图
        tileMap = new TmxMapLoader().load("maps/" + "level" + "000" + ".tmx");

        // 实例化地图渲染器
        mapRender = new OrthogonalTiledMapRenderer(tileMap);
        // 赋值地图瓦片大小
        tileSize = tileMap.getProperties().get("tilewidth", Integer.class);
        // 赋值地图宽度
        mapWidth = tileMap.getProperties().get("width", Integer.class);
        // 赋值地图高度
        mapHeight = tileMap.getProperties().get("height", Integer.class);

        TiledMapTileLayer layer;

        layer = (TiledMapTileLayer) tileMap.getLayers().get("floor");

        createMapLayer(layer, FLOOR);


    }

    private void createMapLayer(TiledMapTileLayer layer, short bits) {

        BodyDef bodyDef = new BodyDef();

        FixtureDef fixtureDef = new FixtureDef();

        for (int row = 0; row < layer.getHeight(); row++) {
            for (int col = 0; col < layer.getWidth(); col++) {

                Cell cell = layer.getCell(col, row);
                if (cell == null)
                    continue;
                if (cell.getTile() == null)
                    continue;


                bodyDef.type = BodyType.StaticBody;
                bodyDef.position.set(
                        (col + 0.5f) * tileSize / RATE,
                        (row + 1f) * tileSize / RATE);
                ChainShape cs = new ChainShape();

                Vector2[] v = new Vector2[3];
                v[0] = new Vector2(-tileSize / 32 / RATE, -tileSize / 32 / RATE);
                v[1] = new Vector2(-tileSize / 32 / RATE, tileSize / 32 / RATE);
                v[2] = new Vector2(tileSize / 32 / RATE, tileSize / 32 / RATE);

                cs.createChain(v);

                fixtureDef.friction = 0;

                fixtureDef.shape = cs;

                fixtureDef.filter.categoryBits = bits;

                fixtureDef.filter.maskBits = PLAYER;

                fixtureDef.isSensor = false;

                world.createBody(bodyDef).createFixture(fixtureDef);
            }
        }
    }

    private void createStar() {

        // 创建萝卜的数组
        stars = new Array<com.hit.RuningGirl.sprite.Star>();
        // 获取对象层
        MapLayer ml = tileMap.getLayers().get("heart");
        // 对象层为空，直接返回
        if (ml == null) return;
        // 实例化星星刚体定义
        BodyDef bodyDef = new BodyDef();
        // 设定刚体类型
        bodyDef.type = BodyType.StaticBody;
        // 实例化夹具
        FixtureDef fixtureDef = new FixtureDef();
        // 实例化圆形图形对象
        CircleShape shape = new CircleShape();
        // 设置圆形刚体半径
        shape.setRadius(8 / RATE);
        // 图形刚体绑定夹具
        fixtureDef.shape = shape;
        // 设定当前刚体为传感器
        fixtureDef.isSensor = true;
        // 设定当前刚体本身碰撞属性
        fixtureDef.filter.categoryBits = STAR;
        // 设定当前刚体目标碰撞属性
        fixtureDef.filter.maskBits = PLAYER;
        // 遍历对象层中对象
        for (MapObject mo : ml.getObjects()) {
            // 星星对象X轴坐标
            float x = 0;
            // 星星对象Y轴坐标
            float y = 0;
            // 获取对象x,y坐标
            if (mo instanceof EllipseMapObject) {
                EllipseMapObject emo = (EllipseMapObject) mo;
                x = emo.getEllipse().x / RATE;
                y = emo.getEllipse().y / RATE;
            }
            // 设定刚体位置
            bodyDef.position.set(x, y);
            // 实例化星星刚体
            Body body = world.createBody(bodyDef);
            // 创建夹具
            body.createFixture(fixtureDef).setUserData("heart");
            // 实例化星星
            com.hit.RuningGirl.sprite.Star s = new com.hit.RuningGirl.sprite.Star(body);
            // 添加星星到当前数组
            stars.add(s);
            // 设定星星用户数据
            body.setUserData(s);
        }
    }

    @Override
    public void update(float dt) {

        handleInput();
        //清屏
        Gdx.gl20.glClear(GL20.GL_COLOR_BUFFER_BIT);
        //位移
        world.step(dt, 6, 2);

        Array<Body> bodies = bcl.getRemoveBodies();
        for (int i = 0; i < bodies.size; i++) {
            Body b = bodies.get(i);
            stars.removeValue((com.hit.RuningGirl.sprite.Star) b.getUserData(), true);
            world.destroyBody(b);
            protagonist.collectStars();

        }
        bodies.clear();


        if (protagonist.getBody().getPosition().x * RATE > mapWidth * tileSize) {
            // 地图声音
            Sound s = assetManager.get("audio/select.wav");
            s.play();

            game.mainScreen.init();

            MainScreen.Debug = false;
            mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            game.setScreen(Yelling.mainScreen);
        }

        if (protagonist.getBody().getPosition().y < 0) {

            Sound s = assetManager.get("audio/contact.wav");
            s.play();

            game.mainScreen.init();

            game.mainScreen.Debug = false;
            //       mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            game.setScreen(game.mainScreen);
        }
        if (protagonist.getBody().getLinearVelocity().x < 0.001f) {

            Sound s = assetManager.get("audio/contact.wav");
            s.play();

            game.mainScreen.init();

            game.mainScreen.Debug = false;

            this.init();

            mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            game.setScreen(game.mainScreen);
        }


        if (bcl.isContactFlame()) {

            Sound s = assetManager.get("audio/contact.wav");
            s.play();

            game.mainScreen.init();

            game.mainScreen.Debug = false;
            mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            game.setScreen(Yelling.mainScreen);
        }
        if (bcl.isTrapContact()) {
            Sound s = assetManager.get("audio/contact.wav");
            s.play();

            game.mainScreen.init();

            game.mainScreen.Debug = false;
            mainScreen.AddLabel(mainScreen.getLabel(protagonist.getStarsCoumt()));
            game.setScreen(Yelling.mainScreen);
        }


    }

    @Override
    public void handleInput() {

//        if (Gdx.input.isKeyJustPressed(Input.Keys.Z)
//                || (Gdx.input.justTouched() && Gdx.input.getX() > Gdx.graphics.getWidth() / 2)) {
//            if (bcl.isOnPlatform()) {
//                protagonist.getBody().applyForceToCenter(20, 100, true);
//            }
//        }

        if (bcl.isOnPlatform()) {
            switch (Yelling.getMyLevel()) {
                case 0:
                    protagonist.getBody().applyForceToCenter(0, 0, true);
                    break;
                case 1:
                    protagonist.getBody().applyForceToCenter(0, 50, true);
                    break;
                case 2:
                    protagonist.getBody().applyForceToCenter(0, 100, true);
                    break;
                case 3:
                    protagonist.getBody().applyForceToCenter(0, 150, true);
                    break;
                default:
                    break;
            }
        }


    }

    private void adjustCamera() {

        if (camera.position.x < camera.viewportWidth / 2) {
            camera.position.x = camera.viewportWidth / 2;
        }

        if (camera.position.x > (tileMap.getProperties().get("width", Integer.class) * tileSize)
                - camera.viewportWidth / 2) {
            camera.position.x = (tileMap.getProperties().get("width", Integer.class) * tileSize)
                    - camera.viewportWidth / 2;
        }
    }

    private void adjustBox2DCamera() {

        if (box2dCamera.position.x < box2dCamera.viewportWidth / 2) {
            box2dCamera.position.x = box2dCamera.viewportWidth / 2;
        }

        if (box2dCamera.position.x > (tileMap.getProperties().get("width", Integer.class)
                / RATE * tileSize) - box2dCamera.viewportWidth / 2) {
            box2dCamera.position.x = (tileMap.getProperties().get("width", Integer.class)
                    / RATE * tileSize) - box2dCamera.viewportWidth / 2;
        }
    }


    @Override
    public void render(float delta) {

        update(delta);


        camera.position.set(protagonist.getPosition().x * RATE + ViewPort_WIDTH
                / 4, ViewPort_HEIGHT / 2, 0);

        adjustCamera();

        camera.update();

        batch.setProjectionMatrix(uiCam.combined);

        gameBack.render(batch);

        statetime += delta;

        batch.setProjectionMatrix(camera.combined);

        protagonist.render(batch, statetime);

        for (int i = 0; i < stars.size; i++) {

            stars.get(i).render(batch, statetime);
        }

        for (int i = 0; i < zaw.size; i++) {

            zaw.get(i).render(batch, statetime);
        }

        for (int i = 0; i < traps.size; i++) {

            traps.get(i).render(batch, statetime);
        }

        for (int i = 0; i < flames.size; i++) {

            flames.get(i).render(batch, statetime);
        }

        batch.setProjectionMatrix(uiCam.combined);


        mapRender.setView(camera);

        mapRender.render();
        if (Box2DDebug) {

            box2dCamera.position.set(protagonist.getPosition().x
                    + ViewPort_WIDTH / 4 / RATE, ViewPort_HEIGHT / 2 / RATE, 0);

            adjustBox2DCamera();

            box2dCamera.update();

            box2dRender.render(world, box2dCamera.combined);


        }
    }
}
